package io.nutz.nutzsite.module.sys.services;

import io.nutz.nutzsite.common.base.Service;
import io.nutz.nutzsite.common.page.TableDataInfo;
import io.nutz.nutzsite.common.utils.DateUtils;
import io.nutz.nutzsite.common.utils.ShiroUtils;
import io.nutz.nutzsite.common.utils.StringUtils;
import io.nutz.nutzsite.common.utils.excel.ImportExcel;
import io.nutz.nutzsite.module.sys.models.Dept;
import io.nutz.nutzsite.module.sys.models.Role;
import io.nutz.nutzsite.module.sys.models.User;
import io.nutz.nutzsite.module.sys.models.Zfjs;
import io.nutz.nutzsite.module.sys.models.Zfxs;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

import org.apache.poi.ss.formula.functions.T;
import org.apache.shiro.crypto.RandomNumberGenerator;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.Sqls;
import org.nutz.dao.pager.Pager;
import org.nutz.dao.sql.Criteria;
import org.nutz.dao.util.DaoUp;
import org.nutz.dao.util.cri.SqlExpressionGroup;
import org.nutz.ioc.loader.annotation.Inject;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.log.Log;
import org.nutz.log.Logs;
import org.nutz.mvc.annotation.Param;
import org.nutz.mvc.upload.TempFile;

import com.google.protobuf.ServiceException;

/**
 * 用户 服务层实现
 *
 * @author haiming
 * @date 2019-04-12
 */
@IocBean(args = {"refer:dao"})
public class UserService extends Service<User> {
	private static final Log log = Logs.get();
    public UserService(Dao dao) {
        super(dao);
    }
    protected Dao dao2;//zf数据库
    @Inject
    private RoleService roleService;
    @Inject
    private MenuService menuService;
    @Inject
    private DeptService deptService;

public NutMap GenNewPwd(String pwd){
	NutMap map=new NutMap();
	RandomNumberGenerator rng = new SecureRandomNumberGenerator();
    String salt = rng.nextBytes().toBase64();
    map.addv("salt", salt);
    if(Strings.isBlank(pwd) ) {    
    	//if(cardid.length()==18) pwd=cardid.substring(12);
    	//else 
    		pwd="123456";
    }

    String hashedPasswordBase64 = new Sha256Hash(pwd, salt, 1024).toBase64();
    map.addv("pwd", hashedPasswordBase64);
    return map;
}
    /**
     * 新增
     *
     * @param user
     * @return
     */
    @Override
    public User insert(User user) {
    	NutMap map=GenNewPwd(user.getPassword());
        user.setSalt(map.getString("salt"));
        user.setPassword(map.getString("pwd"));
        dao().insert(user);
        this.updataRelation(user);
        return user;
    }

    /**
     * 更新
     *
     * @param data
     * @return
     */
    public int update(User data) {
    	User u=fetch(data.getId());
    	if(!data.getPassword().equals(u.getPassword())){//修改密码
	    	NutMap map=GenNewPwd(data.getPassword());
	    	data.setSalt(map.getString("salt"));
	    	data.setPassword(map.getString("pwd"));
    	}
        int count = dao().updateIgnoreNull(data);
        this.updataRelation(data);
        if(data.getId().equals(ShiroUtils.getSysUserId())){//修改自己,要更新一下内存
        	ShiroUtils.setSysUser(fetch(data.getId()));
        }
        return count;
    }

    /**
     * 更新角色
     *
     * @param data
     */
    public void updataRelation(User data) {
        List<String> ids = new ArrayList<>();
        if (data != null && Strings.isNotBlank(data.getRoleIds())) {
            if (Strings.isNotBlank(data.getRoleIds())) {
                ids = Arrays.asList(data.getRoleIds().split(","));
            }
            //清除已有关系
            User tmpData = this.fetch(data.getId());
            this.fetchLinks(tmpData, "roles");
            dao().clearLinks(tmpData, "roles");
        }
        if (ids != null && ids.size() > 0) {
            Criteria cri = Cnd.cri();
            cri.where().andInStrList("id", ids);
            List<Role> roleList = roleService.query(cri);
            data.setRoles(roleList);
        }
        //更新关系
        dao().insertRelation(data, "roles");
    }


    /**
     * 重置密码
     *
     * @param data
     * @return
     */
    public int resetUserPwd(User data) {
    	NutMap map=GenNewPwd(data.getPassword());
    	data.setSalt(map.getString("salt"));
    	data.setPassword(map.getString("pwd"));
    	
        return dao().updateIgnoreNull(data);
    }

    /**
     * 获取角色列表
     *
     * @param userId
     * @return
     */
    public Set<String> getRoleCodeList(String userId) {
        User user =this.fetch(userId);
        this.fetchLinks(user, "roles");
        Set<String> permsSet = new HashSet<>();
        for (Role role : user.getRoles()) {
            if (!role.isStatus() && !role.isDelFlag()) {
                permsSet.add(role.getRoleKey());
            }
        }
        return permsSet;
    }

    /**
     * 获取用户权限
     *
     * @param userId
     * @return
     */
    public Set<String> getPermsByUserId(String userId) {
        Set<String> permsSet = new HashSet<>();
        List<String> menuList = menuService.getPermsByUserId(userId);
        menuList.forEach(menu -> {
            if (Strings.isNotBlank(menu)) {
                permsSet.add(menu);
            }

        });
        return permsSet;
    }

    /**
     * 记录登录信息
     */
    public void recordLoginInfo(User user) {
        user.setLoginIp(ShiroUtils.getIp());
        user.setLoginDate(new Date());
        dao().updateIgnoreNull(user);
    }

    /**
     * 查询用户所属角色组
     *
     * @param userId
     * @return
     */
    public String getUserRoleGroup(String userId) {
        User user = this.fetch(userId);
        user = this.fetchLinks(user, "roles");
        StringBuffer idsStr = new StringBuffer();
        for (Role role : user.getRoles()) {
            idsStr.append(role.getRoleName()).append(",");
        }
        if (Strings.isNotBlank(idsStr.toString())) {
            return idsStr.substring(0, idsStr.length() - 1);
        }
        return idsStr.toString();
    }

    public boolean checkLoginNameUnique(String name) {
        List<User> list = this.query(Cnd.where("id", "=", name));
        if (Lang.isEmpty(list)) {
            return true;
        }
        return false;
    }

	/**
	 * 导入用户数据
	 * @param file 导入的用户数据文件
	 * @param isUpdateSupport 是否更新支持，如果已存在，则进行更新数据
	 * @throws ServiceException 
	 */
	public String importData(TempFile file, Boolean isUpdateSupport) throws ServiceException {
		if (file == null){
			throw new ServiceException("请选择导入的数据文件！");
		}
		int successNum = 0; int failureNum = 0;
		StringBuilder successMsg = new StringBuilder();
		StringBuilder failureMsg = new StringBuilder();
		try{
			ImportExcel ei = new ImportExcel(file, 2, 0);
			List<User> list = ei.getDataList(User.class);
			log.debug("\r\n找到即将导入的用户数: "+list.size());
			for (User user : list) {
				try{
					if(user.getRoleIds()==null || user.getRoleIds()=="") user.setRoleIds("5");
					// 验证是否存在这个用户
					User u =fetch( user.getId());
					if (u == null){
						this.insert(user);
						successNum++;
						successMsg.append("<br/>" + successNum + "、账号 " + user.getId() + " 导入成功");
					} else if (isUpdateSupport){
						this.update(user);
						successNum++;
						successMsg.append("<br/>" + successNum + "、账号 " + user.getId() + " 更新成功");
					} else {
						failureNum++;
						failureMsg.append("<br/>" + failureNum + "、账号 " + user.getId() + " 已存在");
					}
				} catch (Exception e) {
					failureNum++;
					String msg = "<br/>" + failureNum + "、账号 " + user.getId() + " 导入失败：";
					if (e instanceof ConstraintViolationException){
						ConstraintViolationException cve = (ConstraintViolationException)e;
						for (ConstraintViolation<?> violation : cve.getConstraintViolations()) {
							msg += violation.getMessage() + " ("+violation.getPropertyPath()+")";
						}
					}else{
						msg += e.getMessage();
					}
					failureMsg.append(msg);
				}
			}
		} catch (Exception e) {
			failureMsg.append(e.getMessage());
		}
		if (failureNum > 0) {
			failureMsg.insert(0, "很抱歉，导入失败！共 " + failureNum + " 条数据格式不正确，错误如下：");
			throw new ServiceException(failureMsg.toString());
		}else{
			successMsg.insert(0, "恭喜您，数据已全部导入成功！共 " + successNum + " 条，数据如下：");
		}
		return successMsg.toString();
	}
    /**
     * 通过会话序号查询信息
     * 
     * @param sessionId 会话ID
     * @return 在线用户信息
     */

    public User selectOnlineById(String sessionId)
    {
        return this.fetch(Cnd.where("sessionId", "=", sessionId));
    }

    /**
     * 通过会话序号删除信息
     * 
     * @param sessionId 会话ID
     * @return 在线用户信息
     */

    public void deleteOnlineById(String sessionId)
    {
        User userOnline = selectOnlineById(sessionId);
        if (StringUtils.isNotNull(userOnline))
        {
        	userOnline.setUserOnline(false);
        	userOnline.setSessionId(null);
        	updateIgnoreNull(userOnline);
        }
    }
    /**
     * 通过用户id删除在线信息
     * @param uid
     */
    public void deleteOnlineByUid(String uid)
    {
        User userOnline = fetch(uid);
        if (StringUtils.isNotNull(userOnline))
        {
        	userOnline.setUserOnline(false);
        	userOnline.setSessionId(null);
        	updateIgnoreNull(userOnline);
        }
    }
    /**
     * 通过会话序号删除信息
     * 
     * @param sessions 会话ID集合
     * @return 在线用户信息
     */

    public void batchDeleteOnline(List<String> sessions)
    {
        for (String sessionId : sessions)
        {
            User userOnline = selectOnlineById(sessionId);
            if (StringUtils.isNotNull(userOnline))
            {
            	userOnline.setUserOnline(false);
            	userOnline.setSessionId(null);
            	updateIgnoreNull(userOnline);
            }
        }
    }
    /**
     * 查询会话集合
     * 
     * @param expiredDate 会话信息
     */
    public List<User> selectOnlineByExpired(Date expiredDate)
    {
        String lastAccessTime = DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, expiredDate);
        return this.query(Cnd.where("last_access_time","<=",lastAccessTime));
    }
    /**
     * 更新指定入学年份的学生，以班级名为准
     * @param year
     * @return
     */    
	public String updStu(Integer year,String uids)  {		
	  	  ///////临时连接正方数据库/////////////////////
			try {
				DaoUp.me().init("zfdb.properties");
				dao2=DaoUp.me().dao();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return "更新失败"+e.getMessage();
			}
	/////////更新学生/////////////////////////
			try{
				List<Zfxs> xss=null;
				if(uids.length()==0) xss=dao2.query(Zfxs.class, Cnd.where("xzb", "like","%"+ year+"%").and("sfzx", "=", "是"));
				else xss=dao2.query(Zfxs.class, Cnd.where("XH", "in",uids));
				int stun=xss.size();
				String sql="INSERT INTO sys_user (id, user_name,cardid,classg,dept_id,password,salt) VALUES  ";
				String sql2="INSERT INTO sys_user_role (user_id, role_id) VALUES  ";
				for(int j=0;j<stun;j++){//每一学生
					Zfxs xs=xss.get(j);
					User user=new User();
					user.setId(xs.getXh());
					user.setUserName(xs.getXm());
					String cardid=xs.getSfzh();
					user.setCardid(cardid);
					user.setClassg(xs.getXzb());
					user.setRoleIds("5");
					String xy=xs.getYxmc();
					Dept dept=deptService.fetch(Cnd.where("dept_name","like","%"+xy+"%"));
					if(dept==null) user.setDeptId("101");
					else user.setDeptId(dept.getId());

					if(cardid!=null && cardid.length()>=6) user.setPassword(cardid.substring(cardid.length()-6));
					else user.setPassword("123456");
					NutMap map=GenNewPwd(user.getPassword());
			        user.setSalt(map.getString("salt"));
			        user.setPassword(map.getString("pwd"));
			        
					sql+="(";
					sql+="'"+user.getId()+"','"+user.getUserName()+"','"+user.getCardid()+"',"
							+"'"+user.getClassg()+"','"+user.getDeptId()+"',"
							+"'"+user.getPassword()+"','"+user.getSalt()+"'";
					sql+=")";
					sql2+="(";
					sql2+="'"+user.getId()+"',5";
					sql2+=")";
			  		if(j<stun-1) {sql+=",";sql2+=",";}
			  		
					/*
					try{//效率太低
						User u =fetch( user.getId());
						if (u == null){
							this.insert(user);
						} else{
							this.update(user);
						}						
					} catch (Exception e) {
						log.error(e.getMessage());
					}*/
				}
				sql+=" ON DUPLICATE KEY UPDATE  ";
				sql+=" id=VALUES(id),";
				sql+=" user_name=VALUES(user_name),";
				sql+=" cardid=VALUES(cardid),";
				sql+=" classg=VALUES(classg),";
				sql+=" dept_id=VALUES(dept_id),";
				sql+=" password=VALUES(password),";
				sql+=" salt=VALUES(salt)";
				
				sql2+=" ON DUPLICATE KEY UPDATE  ";
				sql2+=" user_id=VALUES(user_id),";
				sql2+=" role_id=VALUES(role_id)";
				if(stun>0){
						try {
				            dao().execute(Sqls.create(sql));
				            dao().execute(Sqls.create(sql2));
				            DaoUp.me().close();
				            return "更新成功";
				        } catch (Exception e) {
				            e.printStackTrace();
				            log.error(e.getMessage());
				            return "更新失败";
				        }
				}
				
			}catch(Exception ex){
				ex.printStackTrace();
				DaoUp.me().close();
				return "更新失败";
			}
		DaoUp.me().close();
		return "0";			
	}
	/**
	 * 更新全体教职工信息
	 * @return
	 */
	public String updTea()  {		
	  	  ///////临时连接正方数据库/////////////////////
			try {
				DaoUp.me().init("zfdb.properties");
				dao2=DaoUp.me().dao();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return "更新失败"+e.getMessage();
			}
	/////////更新学生/////////////////////////
			try{
				List<Zfjs> xss=dao2.query(Zfjs.class, null);
				int stun=xss.size();
				
				for(int j=0;j<stun;j++){//每一老师
					Zfjs xs=xss.get(j);
					User user=new User();
					user.setId(xs.getJgh());
					user.setUserName(xs.getXm());
					String cardid=xs.getSfzjh();
					if(cardid==null || cardid.length()<18)continue;
					user.setCardid(cardid);
					
					user.setRoleIds("4");
					String xy=xs.getDwmc();
					log.debug("\r\n"+xs.getJgh()+","+xy);
					Dept dept=deptService.fetch(Cnd.where("dept_name","like","%"+xy+"%"));
					if(dept==null) user.setDeptId("101");
					else user.setDeptId(dept.getId());
					user.setClassg(xy);
					if(cardid.length()==18) user.setPassword(cardid.substring(12));
					else user.setPassword("");
					try{
						User u =fetch( user.getId());
						if (u == null){
							this.insert(user);
						} else{
							this.update(user);
						}
					} catch (Exception e) {
						log.error(e.getMessage());
					}
				}
			}catch(Exception ex){
				ex.printStackTrace();
				DaoUp.me().close();
				return "更新失败";
			}
		DaoUp.me().close();
		return "0";			
	}
	public TableDataInfo tableListJs(Integer pageNumber, Integer pageSize,String userName,String id){
		Pager pager=null;
		if(Lang.isNotEmpty(pageNumber) && Lang.isNotEmpty(pageSize)){
			pager = this.dao().createPager(pageNumber, pageSize);
		}
		try {
			DaoUp.me().init("zfdb.properties");
			dao2=DaoUp.me().dao();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			return null;
		}
		try{
			Cnd cnd = Cnd.NEW();
			if (!Strings.isBlank(id) || !Strings.isBlank(userName)) {
				SqlExpressionGroup e=Cnd.exps("jgh", "like", "%" + id + "%").or("xm", "like", "%" + userName + "%");
				cnd.and(e);
			}
			List<Zfjs> list = dao2.query(Zfjs.class, cnd, pager);
			return new TableDataInfo(list, this.dao().count(this.getEntityClass(),cnd));
		}finally {
			DaoUp.me().close();
		}

	}
}
